package com.yf.dao;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.yf.annotation.Column;
import com.yf.annotation.ColumnId;
import com.yf.annotation.Table;
import com.yf.utils.RowMapperUtil;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

import javax.annotation.*;
public class DaoAdapter<T> extends JdbcDaoSupport {

	@Resource(name = "yfJdbcTemplate")
	private JdbcTemplate yfJdbcTemplate;

	@PostConstruct
	public void initJdbcTemplate() {
		super.setJdbcTemplate(yfJdbcTemplate);
	}

    private Class<T> clazz;

    public RowMapper<T> rowMapper;


    public DaoAdapter(){
        Type t = getClass().getGenericSuperclass();
        ParameterizedType p = (ParameterizedType) t ;

        final Class<T> c = (Class<T>) p.getActualTypeArguments()[0];
        this.clazz = c;
        rowMapper = new RowMapper<T>() {
            public T mapRow(ResultSet rs, int rowNum) throws SQLException {
                return (T) RowMapperUtil.getRowMapper(c,rs,"");
            }
        };
    }
    /**
     * 获取表名
     * @param
     * @return
     */
    private String getTableName(){

        /**
         * 获取表名
         */
        Table table = this.clazz.getAnnotation(Table.class);
        String tableName = table.name();
        return tableName;
    }

    private String getKey(){
        /**
         * 获取主键
         */
        String key = "";
        Field[] fields = this.clazz.getDeclaredFields();

        for(Field field : fields){

            ColumnId id = field.getAnnotation(ColumnId.class);
            if(id != null){
                String name = id.name();
                key = name;
            }
        }
        return key;
    }

    private String getRealKeyFied(){

        String key = "";
        Field[] fields = this.clazz.getDeclaredFields();

        for(Field field : fields){

            ColumnId id = field.getAnnotation(ColumnId.class);
            if(id != null){
                key = field.getName();
            }
        }
        return key;
    }

    /**
     * 根据id删除数据
     * @param id
     */
    public int executeDeleteById(String id){

        try{

            String sql = "delete from "+this.getTableName()+" where "+this.getKey()+"=?";

            return super.getJdbcTemplate().update(sql,id);
        }catch(Exception e){
            //TODO
            return 0;
        }

    }

    /**
     * 根据id获取list数据
     * @param id
     * @return
     */
    public T findById(String id){

        try {

            String sql = "select * from "+this.getTableName()+" where "+this.getKey()+" = ?";

            return (T)super.getJdbcTemplate().queryForObject(sql,this.rowMapper,id);

        } catch (Exception e) {
            // TODO: handle exception
            return null;
        }

    }

    /**
     * 添加数据
     * @param obj 需要添加的model对象
     * @return
     */
    public int executeAddInfo(Object obj){

        try{
            /** 获取参数的class对象用于获取对象的值*/
            Class clazz = obj.getClass();
            Field []fields = clazz.getDeclaredFields();

            List<Method> methods = RowMapperUtil.getMethodsGet(this.clazz.getMethods());

            List<Object> params = new ArrayList<Object>();

            StringBuilder sb = new StringBuilder();
            StringBuilder quest = new StringBuilder();
            quest.append("(");

            for(int i = 0; i < methods.size();i++){
                Column column = methods.get(i).getAnnotation(Column.class);

                String realFieldName = this.getRealField(methods.get(i));

                Object param = this.getParam(fields, obj, realFieldName);

                params.add(param);

                if(i != (methods.size()-1)){
                    sb.append(column.name()+",");
                    quest.append("?,");
                }else{
                    sb.append(column.name());
                    quest.append("?");
                }
            }
            quest.append(")");

            //这个sql拼接错误了 insert into user(name,phone,duty,id) values(?,?,?,?);应该 是这样
            String sql = "insert into "+this.getTableName()+"("+sb.toString()+")"+" values"+quest.toString();

            return super.getJdbcTemplate().update(sql,params.toArray());
        }catch(Exception e){
            //TODO
            return 0;
        }
    }

    /**
     * 获取真正的属性名称
     * @param method
     * @return
     */
    private String getRealField(Method method){

        //获取对应的属性
        String methodName = method.getName();
        String fieldName = methodName.substring(3).trim();
        String prefix = fieldName.substring(0,1);
        String suffix = fieldName.substring(1);

        //真正的属性值
        String realFildName = prefix.toLowerCase()+suffix;

        return realFildName;
    }

    /**
     * 获取对应字段的属性值
     * @param fields
     * @param obj
     * @param realFieldName
     * @return
     */
    private Object getParam(Field []fields,Object obj,String realFieldName){
        Object param = null;
        try {
            for(Field field : fields){

                if(field.getName().equals(realFieldName)){
                    field.setAccessible(true);//暴力访问
                    param = field.get(obj);
                }
            }
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        return param;
    }

    /**
     * 修改对象信息
     * @param obj 修改对象信息
     * @return
     */
    public int executeUpdate(Object obj){

        try{

            //获取传参对象的class对象目的为了获取属性 值
            Class clazz = obj.getClass();
            //获取所有的属性值
            Field []fields = clazz.getDeclaredFields();


            //用于盛放对应的参数；
            List<Object> params = new ArrayList<Object>();
            //开始组装修改语句
            String update = "update "+this.getTableName()+" set ";

            //获取所有的get方法 为了得到对应数据库表的列名称
            List<Method> methods = RowMapperUtil.getMethodsGet(this.clazz.getMethods());

            //循环拼装sql及对应的值
            for(int i = 0;i<methods.size() ;i++){

                //获取真正的属性名称用于比较
                String realFieldName = this.getRealField(methods.get(i));

                Object param = this.getParam(fields, obj, realFieldName);


                if(i != (methods.size()-1)){
                    Column column = methods.get(i).getAnnotation(Column.class);

                    String name = column.name();

                    if(!name.equals(this.getKey())){
                        update += name+"=?,";
                        params.add(param);
                    }
                }else{
                    Column column = methods.get(i).getAnnotation(Column.class);

                    String name = column.name();

                    if(!name.equals(this.getKey())){
                        update += name+"=?";
                        params.add(param);
                    }
                }
            }

            //获取主键的值
            String keyField = this.getRealKeyFied();
            Object keyValue = this.getParam(fields,obj,keyField);
            params.add(keyValue);

            update = update +" where "+this.getKey()+"=?";

            return super.getJdbcTemplate().update(update,params.toArray());

        }catch(Exception e){
            //TODO
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 分页查询
     * @param searchEntity 查询实体
     * @return
     */
    public List<T> executeGetAllInfo(SearchEntity searchEntity){
        
        try{

            String sql = searchEntity.toSql();
            String totalSql = searchEntity.toPageTotalSql();

            int total = 0;
            if(searchEntity.getPageTotalSearchValues().size() <= 0){
                total = super.getJdbcTemplate().queryForInt(totalSql);
            }else{
                total = super.getJdbcTemplate().queryForInt(totalSql,searchEntity.getPageTotalSearchValues().toArray());
            }
            searchEntity.setTotal(total);

            return (List<T>) super.getJdbcTemplate().query(sql,this.rowMapper,searchEntity.getSearchValues().toArray());

        }catch(Exception e){
            //TODO
            return null;
        }
    }

}
